package com.zcr.es;

import com.zcr.entity.UserEs;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author ZhangCuirong
 * @Date 2024/9/30 11:44
 * @description: ESTest
 */
@Slf4j
@RestController
@RequestMapping("/es")
public class EsController {
    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }
    @PostMapping("/insert")
    public boolean insert(@RequestBody UserEs user){
        EsSourceData esSourceData = new EsSourceData();
        Map<String, Object> data = convert2EsSourceData(user);
        esSourceData.setDocId(user.getDocId().toString());
        esSourceData.setData(data);
        return EsRestClient.insertDoc(getEsIndexInfo(), esSourceData);
    }
@PostMapping("/query")
    public PageResult<UserEs> querySubjectList(@RequestBody UserEs req) {
        PageResult<UserEs> pageResult = new PageResult<>();
        EsSearchRequest esSearchRequest = createSearchListQuery(req);
        SearchResponse searchResponse = EsRestClient.searchWithTermQuery(getEsIndexInfo(), esSearchRequest);

        List<UserEs> userEsList = new LinkedList<>();
        SearchHits searchHits = searchResponse.getHits();
        if (searchHits == null || searchHits.getHits() == null) {
            pageResult.setPageNo(req.getPageNo());
            pageResult.setPageSize(req.getPageSize());
            pageResult.setRecords(userEsList);
            pageResult.setTotal(0);
            return pageResult;
        }
        SearchHit[] hits = searchHits.getHits();
        for (SearchHit hit : hits) {
            UserEs userEs = convertResult(hit);
            if (Objects.nonNull(userEs)) {
                userEsList.add(userEs);
            }
        }
        pageResult.setPageNo(req.getPageNo());
        pageResult.setPageSize(req.getPageSize());
        pageResult.setRecords(userEsList);
        pageResult.setTotal(Long.valueOf(searchHits.getTotalHits().value).intValue());
        return pageResult;
    }
    @PutMapping("/update")
    public boolean update(@RequestBody UserEs user) {
        EsSourceData esSourceData = new EsSourceData();
        Map<String, Object> data = convert2EsSourceData(user);
        esSourceData.setDocId(user.getDocId().toString());
        esSourceData.setData(data);
        return EsRestClient.updateDoc(getEsIndexInfo(), esSourceData);
    }
    @PutMapping("/batchUpdate")
    public boolean batchUpdate(@RequestBody List<UserEs> userList) {
        List<EsSourceData> esSourceDataList=new ArrayList<>();
        for (UserEs user : userList) {
            EsSourceData esSourceData = new EsSourceData();
            Map<String, Object> data = convert2EsSourceData(user);
            esSourceData.setDocId(user.getDocId().toString());
            esSourceData.setData(data);
            esSourceDataList.add(esSourceData);
        }

        return EsRestClient.batchUpdateDoc(getEsIndexInfo(), esSourceDataList);
    }
    @DeleteMapping("/deleteAll")
    public boolean deleteAll() {
        return EsRestClient.delete(getEsIndexInfo());
    }
    @DeleteMapping("/deleteByDocId")
    public boolean deleteByDocId(@RequestBody String docId) {
        return EsRestClient.deleteDoc(getEsIndexInfo(), docId);
    }
    @GetMapping("/isExistDocById/{docId}")
    public  boolean isExistDocById(@PathVariable String docId) {
        return EsRestClient.isExistDocById(getEsIndexInfo(), docId);
    }
    @GetMapping("/getDocById/{docId}")
    public Map<String, Object> getDocById(@PathVariable String docId)
    {
    return EsRestClient.getDocById(getEsIndexInfo(), docId);
    }
    @PostMapping("/getDocByIdAndFields")
    public Map<String,Object> getDocByIdAndFields(@RequestBody String docId, @RequestBody String [] fields) {
        return EsRestClient.getDocById(getEsIndexInfo(), docId, fields);
    }

    @PostMapping("/batchInsertDoc")
    public boolean batchInsertDoc(@RequestBody List<UserEs> userList){
        List<EsSourceData> esSourceDataList = userList.stream().map(user -> {
            EsSourceData esSourceData = new EsSourceData();
            Map<String, Object> data = convert2EsSourceData(user);
            esSourceData.setDocId(user.getDocId().toString());
            esSourceData.setData(data);
            return esSourceData;
        }).collect(Collectors.toList());
        return EsRestClient.batchInsertDoc(getEsIndexInfo(), esSourceDataList);
    }



    private UserEs convertResult(SearchHit hit) {
        Map<String, Object> sourceAsMap = hit.getSourceAsMap();
        if (CollectionUtils.isEmpty(sourceAsMap)) {
            return null;
        }
        UserEs result = UserEs.builder()
                        .docId(MapUtils.getLong(sourceAsMap, EsUserFields.DOC_ID))
                .name(MapUtils.getString(sourceAsMap, EsUserFields.NAME))
                .sex(MapUtils.getString(sourceAsMap, EsUserFields.SEX))
                .age(MapUtils.getInteger(sourceAsMap, EsUserFields.AGE)).
                score(new BigDecimal(String.valueOf(hit.getScore())).multiply(new BigDecimal("100.00").setScale(2, RoundingMode.HALF_UP)))
                .build();



        //处理name的高亮
        Map<String, HighlightField> highlightFields = hit.getHighlightFields();
        HighlightField subjectNameField = highlightFields.get(EsUserFields.NAME);
        if(Objects.nonNull(subjectNameField)){
            Text[] fragments = subjectNameField.getFragments();
            StringBuilder subjectNameBuilder = new StringBuilder();
            for (Text fragment : fragments) {
                subjectNameBuilder.append(fragment);
            }
            result.setName(subjectNameBuilder.toString());
        }

        return result;
    }

    private EsSearchRequest createSearchListQuery(UserEs req) {
        //bq.must  bq.should         bq.minimumShouldMatch(1);
        EsSearchRequest esSearchRequest = new EsSearchRequest();
        BoolQueryBuilder bq = new BoolQueryBuilder();
        MatchQueryBuilder subjectNameQueryBuilder = QueryBuilders.matchQuery(EsUserFields.NAME, req.getName());
        bq.should(subjectNameQueryBuilder);
        subjectNameQueryBuilder.boost(2);


        MatchQueryBuilder subjectTypeQueryBuilder =
                QueryBuilders.matchQuery(EsUserFields.AGE, req.getAge());
        bq.must(subjectTypeQueryBuilder);
        bq.minimumShouldMatch(1);

        HighlightBuilder highlightBuilder = new HighlightBuilder().field("*").requireFieldMatch(false);
        highlightBuilder.preTags("<span style = \"color:red\">");
        highlightBuilder.postTags("</span>");

        esSearchRequest.setBq(bq);
        esSearchRequest.setHighlightBuilder(highlightBuilder);
        esSearchRequest.setFields(EsUserFields.FIELD_QUERY);
        esSearchRequest.setFrom((req.getPageNo() - 1) * req.getPageSize());
        esSearchRequest.setSize(req.getPageSize());
        esSearchRequest.setNeedScroll(false);
        return esSearchRequest;
    }
    private Map<String, Object> convert2EsSourceData(UserEs user) {
        Map<String, Object> data = new HashMap<>();
        data.put(EsUserFields.NAME, user.getName());
        data.put(EsUserFields.AGE, user.getAge());
        data.put(EsUserFields.SEX, user.getSex());
        data.put(EsUserFields.DOC_ID, user.getDocId());
        return data;
    }
    private EsIndexInfo getEsIndexInfo() {
        EsIndexInfo esIndexInfo = new EsIndexInfo();
        esIndexInfo.setClusterName("00d93824a320");
        esIndexInfo.setIndexName("subject_index");
        return esIndexInfo;
    }



}
